package brainfuck

import (
	"bufio"
	"fmt"
	"os"
)

const MEMORY_SIZE = 30000

type Interpreter struct {
	memory    [MEMORY_SIZE]byte
	ptr       int
	pc        int
	program   []byte
	input     *bufio.Reader
	output    *bufio.Writer
	loopStack []int
}

func NewInterpreter(program string) *Interpreter {
	return &Interpreter{
		program:   []byte(program),
		input:     bufio.NewReader(os.Stdin),
		output:    bufio.NewWriter(os.Stdout),
		loopStack: make([]int, 0),
	}
}

// Run 方法用于执行 Brainfuck 程序，返回执行过程中可能出现的错误。
func (i *Interpreter) Run() error {
	// 当程序计数器（pc）小于程序长度时，持续执行程序
	for i.pc < len(i.program) {
		// 根据当前程序计数器指向的字符，执行相应的操作
		switch i.program[i.pc] {
		case '>':
			// 指针右移一位
			i.ptr++
			// 如果指针超出内存范围，循环回到内存起始位置
			if i.ptr >= MEMORY_SIZE {
				i.ptr = 0 // 循环回到内存起始位置
			}
		case '<':
			// 指针左移一位
			i.ptr--
			// 如果指针小于 0，循环回到内存末尾
			if i.ptr < 0 {
				i.ptr = MEMORY_SIZE - 1 // 循环回到内存末尾
			}
		case '+':
			// 当前指针指向的内存单元的值加 1
			i.memory[i.ptr]++
		case '-':
			// 当前指针指向的内存单元的值减 1
			i.memory[i.ptr]--
		case '.':
			// 输出当前指针指向的内存单元的值对应的 ASCII 字符
			if err := i.output.WriteByte(i.memory[i.ptr]); err != nil {
				return err
			}
			// 刷新输出缓冲区，确保字符被立即输出
			i.output.Flush()
		case ',':
			// 从标准输入读取一个字节
			val, err := i.input.ReadByte()
			if err != nil {
				return err
			}
			// 将读取到的字节存储到当前指针指向的内存单元
			i.memory[i.ptr] = val
		case '[':
			// 如果当前指针指向的内存单元的值为 0，则跳过匹配的 ]
			if i.memory[i.ptr] == 0 {
				// 跳过匹配的]
				depth := 1
				for depth > 0 {
					i.pc++
					if i.pc >= len(i.program) {
						return fmt.Errorf("unmatched [")
					}
					switch i.program[i.pc] {
					case '[':
						depth++
					case ']':
						depth--
					}
				}
			} else {
				// 否则，将当前程序计数器的值压入循环栈
				i.loopStack = append(i.loopStack, i.pc)
			}
		case ']':
			// 如果循环栈为空，说明 ] 没有匹配的 [
			if len(i.loopStack) == 0 {
				return fmt.Errorf("unmatched ]")
			}
			// 如果当前指针指向的内存单元的值不为 0，跳回到匹配的 [ 处
			if i.memory[i.ptr] != 0 {
				i.pc = i.loopStack[len(i.loopStack)-1] - 1
			} else {
				// 否则，从循环栈中弹出最后一个元素
				i.loopStack = i.loopStack[:len(i.loopStack)-1]
			}
		}
		// 程序计数器加 1，指向下一个字符
		i.pc++
	}
	// 程序执行完毕，没有错误，返回 nil
	return nil
}
